#include "DOpenGLPointCloud.h"


DOpenGLPointCloud::DOpenGLPointCloud(void)
{
	isInited = false;
	pointNum = 0;
	vao = 0;
	vbo_vertex = 0;
	vbo_norm = 0;
	vbo_color = 0;
	modelMatrix=glm::mat4(1.0f);
}


DOpenGLPointCloud::~DOpenGLPointCloud(void)
{
	CleanUp();
}

bool DOpenGLPointCloud::Init()
{
	glGenVertexArrays(1,&vao);
	if(vao == 0)goto InitFailed;
	glBindVertexArray(vao);
	
	glGenBuffers(1,&vbo_vertex);
	glGenBuffers(1,&vbo_norm);
	glGenBuffers(1,&vbo_color);

	if(vbo_vertex==0||vbo_norm==0 ||vbo_color==0)goto InitFailed;
	isInited = true;
	glBindBuffer(GL_ARRAY_BUFFER,0);
	glBindVertexArray(0);
	return true;
InitFailed:
	CleanUp();
	return false;
}
bool DOpenGLPointCloud::IsInited() const
{
	return isInited;
}
void DOpenGLPointCloud::CleanUp()
{
	if(vbo_vertex)glDeleteBuffers(1,&vbo_vertex);
	if(vbo_norm)glDeleteBuffers(1,&vbo_norm);
	if(vbo_color)glDeleteBuffers(1,&vbo_color);
	if(vao)glDeleteVertexArrays(1,&vao);
}
bool DOpenGLPointCloud::LoadPointCloud(const GLfloat* data, int float_per_point, int pointNum_, GLenum usage)
{
	if(!isInited) return false;
	int totalSize = pointNum_*float_per_point*sizeof(float);
	glBindVertexArray(vao);
	glBindBuffer(GL_ARRAY_BUFFER,vbo_vertex);
	glVertexAttribPointer(0, float_per_point, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(0);
	glBufferData(GL_ARRAY_BUFFER, totalSize,data,usage);

	
	glBindBuffer(GL_ARRAY_BUFFER,0);
	glBindVertexArray(0);
	pointNum = pointNum_;
	return true;
}
bool DOpenGLPointCloud::LoadPointCloudNorm(const GLfloat* data, int float_per_point, int pointNum_, GLenum usage)
{
	if(!isInited) return false;
	int totalSize = pointNum_*float_per_point*sizeof(float);
	glBindVertexArray(vao);
	glBindBuffer(GL_ARRAY_BUFFER,vbo_norm);
	glVertexAttribPointer(1, float_per_point, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(1);
	glBufferData(GL_ARRAY_BUFFER, totalSize,data,usage);
	
	glBindBuffer(GL_ARRAY_BUFFER,0);
	glBindVertexArray(0);
	pointNum = pointNum_;
	return true;
}
bool DOpenGLPointCloud::LoadPointCloudColor(const GLfloat* data, int float_per_point, int pointNum_, GLenum usage)
{
	if(!isInited) return false;
	int totalSize = pointNum_*float_per_point*sizeof(float);
	glBindVertexArray(vao);
	glBindBuffer(GL_ARRAY_BUFFER,vbo_color);
	glVertexAttribPointer(2, float_per_point, GL_FLOAT, GL_FALSE, 0, 0);
	glEnableVertexAttribArray(2);
	glBufferData(GL_ARRAY_BUFFER, totalSize,data,usage);
	
	glBindBuffer(GL_ARRAY_BUFFER,0);
	glBindVertexArray(0);
	pointNum = pointNum_;
	return true;
}

void DOpenGLPointCloud::ResetModelMatrix()
{
	modelMatrix=glm::mat4(1.0f);
}

void DOpenGLPointCloud::SetModelMatrix(const float pose_R[9], const float pose_T[3])
{
	modelMatrix=glm::mat4(pose_R[0],pose_R[1],pose_R[2],0,
		pose_R[3],pose_R[4],pose_R[5],0,
		pose_R[6],pose_R[7],pose_R[8],0,
		pose_T[0],pose_T[1],pose_T[2],1);
}
const float* DOpenGLPointCloud::GetModelMatrixPtr() const
{
	return glm::value_ptr(modelMatrix);
}



bool DOpenGLPointCloud::DrawPointCloud(GLint first, int count, int render_modelMatrix_position) const
{
	if(!isInited) return false;
	glUniformMatrix4fv(render_modelMatrix_position, 1, GL_FALSE, GetModelMatrixPtr());
	glBindVertexArray(vao);
	glDrawArrays(GL_POINTS, first, count);
	glBindVertexArray(0);
	return true;
}
bool DOpenGLPointCloud::DrawPointCloud(int render_modelMatrix_position) const
{
	if(!isInited) return false;
	glUniformMatrix4fv(render_modelMatrix_position, 1, GL_FALSE, GetModelMatrixPtr());
	glBindVertexArray(vao);
	glDrawArrays(GL_POINTS, 0, pointNum);
	glBindVertexArray(0);
	return true;
}

GLuint DOpenGLPointCloud::GetVAOHandle() const
{
	return vao;
}
GLuint DOpenGLPointCloud::GetVBOHandle() const
{
	return vbo_vertex;
}
